home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Languages / Mops 2.7 / Mops source / Toolbox classes / Ctl < prev    next >
Encoding:
Text File  |  1995-11-26  |  11.1 KB  |  427 lines  |  [TEXT/MSET]

  1. \ Control support.  Mops version.
  2. \ Nov 90        Added Bob Loewenstein's improvements
  3. \ Nov 91        Controls now owned by views, not windows
  4. \ May 92        "New-style" controls
  5. \ Sept 93    mrh    Controls are now views
  6.  
  7. need    view
  8.  
  9. \ With Mops 2.4 we are changing controls yet again - although hopefully
  10. \ without affecting existing code (much).
  11.  
  12. \ A control is now a subclass of view.  In other respects it is more or less
  13. \ what TitledCtl was in Mops 2.3.  This means that the original Control class
  14. \ has now gone for good - I hope everyone has already changed over to the
  15. \ new scheme, since hardly any changes will be needed.  The main change
  16. \ is that now we don't set the viewRect directly - method SetViewRect:
  17. \ doesn't even exist any longer.  Instead you use setBounds: and setJust:.
  18. \ See the comments in file View.
  19.  
  20. \ We always need to refer to controls with a GrafPort-relative coordinate
  21. \ origin.  This is because the system keeps a copy of the controls Rect
  22. \ in its own data structure (which the control handle points to), and uses
  23. \ this in FindControl.  Thus in our DRAW: method here we have to reset the
  24. \ origin (the CallFirst code will have set it so the top left of the viewRect
  25. \ is (0, 0), which we usually want for views, but not here).
  26.  
  27. \ control types:
  28.  
  29.     0    constant    BUTTONID
  30.     1    constant    CHECKID
  31.     2    constant    RADIOID
  32.    16    constant    VSID
  33.  
  34. \ control part codes:
  35.  
  36.   10    constant  INBUTTON            \ simple button
  37.   11    constant  INCHECKBOX        \ check box or radio button
  38.  129    constant  INTHUMB
  39.   20    constant  INUPBUTTON        \ up arrow in scroll bar
  40.   21    constant  INDOWNBUTTON        \ down arrow
  41.   22    constant  INPAGEUP
  42.   23    constant  INPAGEDOWN
  43.  
  44.  
  45.    8    constant  USEWFONT        \ Add to ID if title in application font
  46.  
  47. variable    TheCTL            \ used for FindControl call
  48.  
  49. 0    value    ThisCTL            \ holds addr of control just clicked on
  50.  
  51.  
  52. : TWIDTH    \ ( addr len -- width )
  53.             \ Returns width of string in current font
  54.     str255 >r  word0  r>  call StringWidth  word0  ;
  55.  
  56.  
  57. \ CtlProc is the procedure to be executed when a control is being tracked.
  58. \ Our CLICK: method will have put the control object's addr in thisCtl.
  59. \ The system passes us the control handle, but what we really need is the
  60. \ object's addr so we just NIP the handle.
  61.  
  62. : CtlEXEC        \ ( part# -- )
  63.     exec: [ thisCtl ]  ;
  64.  
  65. :proc CtlPROC        \  ( ^ctl int:part -- )
  66.     word0  nip  ctlExec  ;proc
  67.  
  68.  
  69. \            ======================
  70.  
  71. \ Control is the basic control class.
  72.  
  73. :class    CONTROL      super{ view }
  74. record
  75. {    int            PROCID
  76.     int            RESID
  77.     handle        CTLHNDL
  78.     int            MyVALUE
  79.     int            TitleLen
  80. 32    bytes        TITLE
  81. }
  82.  
  83. :m PUTRESID:    \ ( resID -- )
  84.     put: resID   ;m 
  85.  
  86. :m HANDLE:    \ ( -- ctlhndl )
  87.     get: ctlHndl  ;m 
  88.  
  89. :m EXEC:    \ ( part# -- )  performs action for control
  90.     IF  exec: clickHndlr  THEN  ;m 
  91.  
  92. :m HIDE:    get: Ctlhndl  call HideControl  ;m 
  93.  
  94. :m SHOW:    get: Ctlhndl  call ShowControl  ;m 
  95.  
  96.  
  97. :m PUT:  { theVal -- }    \ Sets the ctl value.
  98.     get: alive?
  99.     IF    addr: viewRect  call ClipRect
  100.         theVal  get: ctlHndl  swap makeint  call SetCtlValue
  101.     THEN
  102.     theVal  put: myValue  ;m 
  103.  
  104. :m GET:        \ ( -- val )  Some ctls may need original value,
  105.             \        e.g. scroll bar
  106.     get: alive?  get: enabled?  and
  107.     IF        word0  get: ctlHndl  call getCtlValue  word0
  108.             dup  put: myValue            \ may have been different, e.g. on a
  109.                                         \  scroll bar thumb drag
  110.     ELSE    get: myValue
  111.     THEN  ;m 
  112.  
  113.  
  114. :m MOVED:  { \ oldL oldT oldR oldB newL newT newR newB -- }
  115.     get: viewRect -> oldB  -> oldR -> oldT -> oldL
  116.     update: viewRect                \ Old ctl posn must be redrawn
  117.     bounds>viewRect: self
  118.     get: viewRect  -> newB  -> newR -> newT -> newL
  119.     nil?: ctlHndl
  120.     NIF    oldL newL <>
  121.         oldT newT <> or
  122.         oldR newR <> or
  123.         oldB newB <> or
  124.         IF    
  125.             update: viewRect        \ whatever was behind must be redrawn
  126.             hide: self
  127.             get: ctlHndl  newR newL -  newB newT -  pack  call SizeControl
  128.             get: ctlHndl  newL newT pack  call MoveControl
  129.             show: self
  130.             addr: viewRect  call ValidRect
  131.         THEN
  132.     THEN
  133.     childrenMoved: self                \ Hmmm - should a control have children?
  134. ;m
  135.     
  136.  
  137. \ NEW: ( -- )  calls the Toolbox to fire up the control.
  138.  
  139. \ When to call new: super ?  If we do it at the start, child controls
  140. \ will be drawn first which isn't what we want.  If we do it at the end,
  141. \ bounds>viewrect won't have been done so the viewrect won't be valid.
  142. \ So we'd better not do it at all, but completely override.
  143.  
  144. :m NEW:
  145.     setupNew: super
  146.  
  147.     0                                        \ for return handle
  148.     window: self
  149.     addr: viewRect
  150.     addr: title  get: titleLen  str255
  151.     w 256                                    \ visible - use 0 for invisible
  152.     word0  word0  w 1  int: procid            \ initial value, min, max, procID
  153.     0                                        \ initial refCon - we don't use it
  154.     call NewControl   put: ctlHndl
  155.     get: myValue  put: self
  156.  
  157.     windupNew: self  ;m
  158.  
  159.  
  160. :m GETNEW:  { theView -- }        \ Uses a resource.
  161.     setupNew: self
  162.     
  163.     0  int: resID  window: self
  164.     call GetNewControl  put: ctlHndl
  165.     get: myValue  put: self
  166.  
  167.     windupNew: self  ;m
  168.  
  169.  
  170. :m DRAW:
  171.     (draw): super
  172.     0  call SetOrigin  addr: viewRect  call ClipRect
  173.     get: ctlHndl  call Draw1Control
  174. ;m
  175.  
  176.  
  177.  
  178. :m CLICK:  { \ svClickHndlr part ^ctl action1 action2 x y -- b }
  179.  
  180.     \ Returns true if we've handled the click.  A gotcha here is that
  181.     \ we need to call click: super so that View can check if the click
  182.     \ is really for us, but View mustn't execute the click handler since
  183.     \ the standard action for controls is that the click only counts if
  184.     \ the mouse is still in the control at mouse-up (TrackControl handles
  185.     \ this).  We therefore remove the click handler while calling new: super,
  186.     \ then put it back!
  187.  
  188.     get: clickHndlr -> svClickHndlr
  189.     ['] null  put: clickHndlr    \ Don't want View to execute the clickHndlr
  190.     click: super                \ Do the standard View stuff first
  191.     svClickHndlr  put: clickHndlr
  192.     NIF  false  EXIT  THEN        \ Click wasn't for us - get out
  193.  
  194. \ OK, we know the click was on this control, but we still need to call
  195. \ FindControl to get the right part code, and TrackControl to do any
  196. \ necessary tracking.
  197.  
  198.     ^base -> thisCtl                \ For the TrackControl :proc routine
  199.  
  200.     word0 mpoint get: ^myWind theCtl  call FindControl
  201.     word0 -> part
  202.     theCtl @ -> ^ctl                \ ctl handle
  203.     ^ctl  get: ctlHndl <>            \ really, they ought to be the same
  204.     IF  false  EXIT  THEN            \ if not, we just return false
  205.                                     \  (any better ideas?)
  206.     part
  207.     CASE[ inThumb ], [ inCheckBox ], [ inButton ]=>
  208.                                 \ we only execute these after mouseUp -
  209.         0 ->  action1            \ there's no action while mouse down.  For
  210.                                 \ this case we have to pass a toolBox NIL
  211.                                 \ to TrackControl (i.e. zero)
  212.         ['] ctlExec  -> action2
  213.     DEFAULT=>
  214.         drop  ['] ctlproc -> action1  ['] drop -> action2
  215.     ]CASE
  216.     ^ctl
  217.     IF    addr: viewRect  call ClipRect        \ so hiliting shows up!
  218.         word0  ^ctl  mpoint  action1  call TrackControl  word0
  219.         action2  execute  true
  220.     ELSE    false
  221.     THEN  ;m
  222.  
  223.  
  224. :m HILITE:  { hiliteState -- }  \ Hilites a part or entire control
  225.     get: alive?  0EXIT
  226.     addr: viewRect  call ClipRect
  227.     get: ctlHndl  hiliteState  makeint
  228.     call HiliteControl
  229.     addr: viewRect  call ValidRect  ;m
  230.                 \ Otherwise it can get drawn twice, such as if when a window
  231.                 \ is activated it also gets uncovered, there'll be an update
  232.                 \ event coming.
  233.  
  234. :m DISABLE:        255    hilite: self  false put: enabled?  ;m 
  235. :m ENABLE:        0    hilite: self  true  put: enabled?  ;m 
  236.  
  237.  
  238. :m SETTITLE:    \ ( addr len -- )
  239.     32 min  dup put: titleLen  addr: title  swap  cmove
  240.     nil?: ctlHndl
  241.     NIF
  242.         addr: title  get: titleLen  str255
  243.         get: ctlHndl  swap  call setCTitle
  244.     THEN  ;m 
  245.  
  246. :m GETTITLE:    \ ( -- addr len )
  247.     addr: title  get: titleLen  ;m 
  248.  
  249.  
  250. :m RELEASE:
  251.     get: ctlHndl  call DisposControl  nilH put: ctlHndl
  252.     release: super  ;m 
  253.  
  254.  
  255. :m CLASSINIT:    \ Sets default control to a standard button
  256.     classinit: super
  257.     buttonID  put: resID
  258.     ['] null  setClick: self
  259.     clear: titleLen  ;m 
  260.  
  261. ;class
  262.  
  263.  
  264. \ Class TitledCtl just adds a convenient INIT: method for setting up a control
  265. \ with a title, where the width of the control's rect is determined by what the
  266. \ title is.  We assume the font will be Chicago and the height of the control
  267. \ is 20.  Override as necessary.
  268.  
  269. :class    TITLEDCTL  super{ control }
  270.  
  271. \ INIT: ( x y addr len -- )  sets up the control with a title.
  272. \ x and y are the initial top left Bounds values (using whatever justification
  273. \ is in effect).  (addr len) gives the title.
  274.  
  275. :m INIT: { x y addr len \ titleWidth -- }
  276.     len 32 min  -> len
  277.     len  put: titleLen  addr  addr: title  len  cmove
  278.     addr len tWidth  -> titleWidth
  279.     x  y  x titleWidth + 20 +  y 20 +  setBounds: self
  280. ;m
  281.  
  282. ;class
  283.  
  284.  
  285. :class    BUTTON    super{ titledCtl }
  286. ;class
  287.  
  288. :class    CHECKBOX  super{ titledCtl }
  289.   :m CLASSINIT:    classinit: super   checkID  put: procID  ;m
  290. ;class
  291.  
  292. :class    RADIOBUTTON    super{ titledCtl }
  293.   :m CLASSINIT:    classinit: super  radioID  put: procID  ;m
  294. ;class
  295.  
  296.  
  297.  
  298. \ VSCROLL is the class for vertical scroll bars.  HSCROLL is a subclass
  299. \ to be used for horizontal scroll bars.
  300.  
  301. \ Default handlers for clicks in scroll bar arrows:
  302.  
  303. : LNUP    get: [ thisCtl ]  1-  put: [ thisCtl ]  ;
  304. : LNDN    get: [ thisCtl ]  1+  put: [ thisCtl ]  ;
  305.  
  306.  
  307. :class    VSCROLL  super{ control }
  308. record
  309. {    int            MINVAL
  310.     int            MAXVAL
  311.     bool        HORIZ?        \ True if this is really
  312.                             \  a horizontal scroll bar.
  313. }
  314. 5    ordered-col    PARTS
  315. 5    x-array        ACTIONS
  316.  
  317. :m ACTIONS:    \ ( up dn pgUp pgDn thumb 5 -- )
  318.             \ Loads the actions for the parts of the scroll bar, from 
  319.             \  the given xt list.
  320.     put: actions   clear: parts
  321.     129 23 22 21 20  5 FOR  add: parts  NEXT  ;m 
  322.  
  323. :m EXEC:    \ ( part# -- )  Performs action for part no.
  324.     indexOf: parts  IF  exec: actions  THEN  ;m 
  325.  
  326.  
  327. :m PUT:
  328.     get: maxVal  min  get: minVal  max  put: super  ;m
  329.  
  330. :m PUTMAX:  { n -- }
  331.     n  put: maxVal
  332.     get: alive?  0EXIT
  333.     get: ctlHndl  n makeint  call SetMaxCtl  ;m
  334.  
  335. :m PUTMIN:  { n -- }
  336.     n  put: minVal
  337.     get: alive?  0EXIT
  338.     get: ctlHndl  n makeint  call SetMinCtl  ;m
  339.  
  340. :m PUTRANGE:    \ ( lo hi -- )
  341.     putMax: self  putMin: self  ;m
  342.  
  343. :m INIT:  { left top len -- }    \ for convenience and backward compatibility
  344.     left top
  345.     get: horiz?
  346.     IF        left len +  top 16 +
  347.     ELSE    left 16 +    top len +
  348.     THEN
  349.     setBounds: self  ;m
  350.  
  351.  
  352. :m HIDE:
  353.     get: Ctlhndl  call HideControl
  354.     window: self call DrawGrowIcon
  355.         \ Nov95 JRF properly hide scrollbar in inactive window
  356.         \ In this context DrawGrowIcon will draw the scroll frame only,
  357.         \ which is just what we want.
  358. ;m
  359.  
  360. :m NEW:
  361.     new: super
  362.     get: minVal  get: maxVal  putRange: self  ;m
  363.                                     \ set min and max in ctlHndl
  364.  
  365. :m CLASSINIT:
  366.     classinit: super
  367.     16  put: procID
  368.     XTS{ lnup  lndn  null null null }  actions: self  ;m
  369.  
  370. ;class
  371.  
  372.  
  373. :class    HSCROLL  super{ vscroll }
  374.     :m CLASSINIT:    true put: horiz?   classinit: super  ;m 
  375. ;class
  376.  
  377.  
  378.  
  379. endload
  380.  
  381. need window+
  382.  
  383.  
  384. \ Testing - this sets up a view with a button and scroll bar:
  385.  
  386. window+    WW            \ for display
  387. view    VV            \ Main view
  388. button    BB            \ A child view which is a button
  389. vscroll    VS            \ Another child view which is a vert scroll bar
  390.  
  391.  
  392. 40 40 300 200    setBounds: vv
  393.  
  394. 10 10  " Click here"    init: bb
  395.  
  396. parRight parTop parRight parBottom  setJust: vs
  397. -36 20 -20 -10    setBounds: vs
  398.  
  399.  
  400. : Drawit    draw: tempRect  ;        \ A draw handler which just draws the viewRect
  401.  
  402. : DrawVV    draw: vv  ;                \ Draw handler for fWind for test
  403.  
  404. : Clicked
  405.     noclip
  406.     ." clicked " .id: [self] cr
  407. \ Now we expand vv a bit to check if the scroll bar moves and resizes:
  408.     getBounds: vv
  409.     10 +
  410.     swap 20 + swap
  411.     setBounds: vv  moved: vv  ;
  412.  
  413.  
  414. : contentClick            \ New content click handler for fWind
  415.             click: vv  drop  ;
  416.             
  417. ' drawit    setDraw: vv
  418.  
  419. ' clicked    dup setclick: vv  setclick: bb
  420.  
  421. : GO
  422.     cls
  423.     bb addview: vv  vs addview: vv
  424.     0 50 putRange: vs
  425.     vv test: ww                \ Normally done automatically from NEW: in Window+
  426. ;
  427.